#include "gx_hashfcn.h"
#include "gx_primetable.h"
#include "gx_err.h"

unsigned int BKDRHash(char *str)
{
	unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
	unsigned int hash = 0; 

	while (*str)
	{    
		hash = hash * seed + (*str++);
	}    

	return (hash & 0x7FFFFFFF);
}


HASHFCN * hashfcn_new( int m )
{
    HASHFCN * p;
    static int one=1;
    
    if( one ) /* one time init */
    {
        srand( (unsigned) time(0) );
        one = 0;
    }
    
    // This can make all of the hashing static for testing.
    //#define rand() 0
    
    p = (HASHFCN*) calloc( 1,sizeof(HASHFCN) );
    if( !p )
        return 0;
    
    p->seed     = nearest_prime( (rand()%m)+3191 );
    p->scale    = nearest_prime( (rand()%m)+709 );
    p->hardener = (rand()*rand()) + 133824503;
    
    p->hash_fcn   = &hashfcn_hash;
    p->keycmp_fcn = &memcmp;
       
    return p;
}

void hashfcn_free( HASHFCN * p )
{
   if( p )
   {
       free( p);
   }
}

void hashfcn_static( HASHFCN * p )
{
    p->seed     = 3193;
    p->scale    = 719;
    p->hardener = 133824503;
}

unsigned hashfcn_hash( HASHFCN * p, unsigned char *d, int n )
{
    unsigned hash = p->seed;
    while( n )
    {
        hash *=  p->scale;
        hash += *d++;
        n--;
    }
    return hash ^ p->hardener;
}


int hashfcn_set_keyops( HASHFCN *h,
                          unsigned (*hash_fcn)( HASHFCN * p,
                                                unsigned char *d,
                                                int n),
                          int (*keycmp_fcn)( const void *s1,
                                             const void *s2,
                                             size_t n))
{
    if(h && hash_fcn && keycmp_fcn)
    {
        h->hash_fcn   = hash_fcn;
        h->keycmp_fcn = keycmp_fcn;

        return SUCCESS;
    }

    return PARAMETER_ERROR;
}

